import traceback
from pymongo import MongoClient
from flask import Flask, request
import os
from datetime import datetime
import pymysql, redis
from urllib import parse
from dbutils.pooled_db import PooledDB
import utilsapp
import psutil
from json import JSONEncoder
from utilsapp.mysql_con import db_connect

from apps.backstage import backstage
from apps.waveacq import bluePrint as waveacq
from apps.config import bluePrint as config
from apps.wavecoll import bluePrint as wavecoll
from apps.knowledge import bluePrint as knowledge
from apps.openapi import bluePrint as openapi
from apps.openapi_common import bluePrint as openapi_common
from apps.diagnosis import bluePrint as diagnosis
from apps.diag import bluePrint as diag
from apps.point import bluePrint as point
from apps.repair import bluePrint as repair
from apps.deviceRepairlog import bluePrint as device_repairlog
from apps.deviceType import deviceType
from apps.eigenvalue import eigenvalue
from apps.index import construct_blueprint_index
from apps.order import order
from apps.region import region
from apps.report import report
from apps.role import role
from apps.selfreport import selfreport
from apps.health import bluePrint as health
from apps.lubrication import bluePrint as lubrication
from apps.statistics import bluePrint as statistics
from apps.sensor import sensor
from apps.spare import spare
from apps.log import bluePrint as log
from apps.wave import bluePrint as wave
from apps.sensorType import sensorType
from apps.sys_eig import eigenvalue as sys_eig
from apps.sys_wave import eigenvalue as sys_wave
from apps.project import project
from apps.model_group import bluePrint as model_group
from apps.set import set_
from apps.spec import spec
from apps.sthred import sthred
from apps.trouble import trouble
from apps.warn import warn
from apps.notice import bluePrint as notice
from apps.menum import bluePrint as menum
from apps.message import bluePrint as message
from apps.device import device
from apps.oiling import bluePrint as oiling
from apps.baoxiu import bluePrint as baoxiu
from apps.mqtt import bluePrint as mqtt
from apps.part import bluePrint as part
from apps.store import bluePrint as store
from apps.bearing import bluePrint as bearing
from apps.chat import bluePrint as chat
from apps.user import user, verify_token
from apps.algorithm import bluePrint as algorithm
from apps.algorithmModel import bluePrint as algorithmModel
from apps.algorithmGroup import bluePrint as algorithmGroup
from apps.algorithmConfig import bluePrint as algorithmConfig
from apps.algorithmWarn import bluePrint as algorithmWarn
from apps.algorithmNotice import bluePrint as algorithmNotice
from apps.algtest import bluePrint as algtest
from apps.txl import txl
from apps.energy import energy

# 手机端
from blueprint.authority import authority
from blueprint.home import home
from blueprint.user import appuser
from blueprint.wxnotify import wxnotify


def reg_route(app):
    app.json_encoder = CustomJSONEncoder
    app.register_blueprint(knowledge, url_prefix="/api/knowledge")
    app.register_blueprint(algtest, url_prefix="/api/algtest")
    app.register_blueprint(point, url_prefix="/api/point")
    app.register_blueprint(repair, url_prefix="/api/repair")
    app.register_blueprint(diagnosis, url_prefix="/api/diagnosis")
    app.register_blueprint(baoxiu, url_prefix="/api/baoxiu")
    app.register_blueprint(menum, url_prefix="/api/menum")
    app.register_blueprint(mqtt, url_prefix="/api/mqtt")
    app.register_blueprint(part, url_prefix="/api/part")
    app.register_blueprint(store, url_prefix="/api/store")
    app.register_blueprint(bearing, url_prefix="/api/bearing")
    app.register_blueprint(chat, url_prefix="/api/chat")
    app.register_blueprint(health, url_prefix="/api/health")
    app.register_blueprint(lubrication, url_prefix="/api/lubrication")
    app.register_blueprint(statistics, url_prefix="/api/statistics")
    app.register_blueprint(diag, url_prefix="/api/diag")
    app.register_blueprint(role, url_prefix="/api/role")
    app.register_blueprint(user, url_prefix="/api/user")
    app.register_blueprint(sensor, url_prefix="/api/sensor")
    app.register_blueprint(spare, url_prefix="/api/spare")
    app.register_blueprint(region, url_prefix="/api/region")
    app.register_blueprint(sys_eig, url_prefix="/api/sys_eig")
    app.register_blueprint(sys_wave, url_prefix="/api/sys_wave")
    app.register_blueprint(log, url_prefix="/api/log")
    app.register_blueprint(wave, url_prefix="/api/wave")
    app.register_blueprint(device, url_prefix="/api/device")
    app.register_blueprint(backstage, url_prefix="/api/backstage")
    app.register_blueprint(waveacq, url_prefix="/api/waveacq")
    app.register_blueprint(wavecoll, url_prefix="/api/wavecoll")
    app.register_blueprint(config, url_prefix="/api/config")
    app.register_blueprint(deviceType, url_prefix="/api/deviceType")
    app.register_blueprint(device_repairlog, url_prefix="/api/device_repairlog")
    app.register_blueprint(sensorType, url_prefix="/api/sensorType")
    app.register_blueprint(project, url_prefix="/api/project")
    app.register_blueprint(eigenvalue, url_prefix="/api/eigenvalue")
    app.register_blueprint(trouble, url_prefix="/api/trouble")
    app.register_blueprint(warn, url_prefix="/api/warn")
    app.register_blueprint(spec, url_prefix="/api/spec")
    app.register_blueprint(order, url_prefix="/api/order")
    app.register_blueprint(notice, url_prefix="/api/notice")
    app.register_blueprint(message, url_prefix="/api/message")
    app.register_blueprint(oiling, url_prefix="/api/oiling")
    app.register_blueprint(report, url_prefix="/api/report")
    app.register_blueprint(sthred, url_prefix="/api/sthred")
    app.register_blueprint(selfreport, url_prefix="/api/selfreport")
    app.register_blueprint(set_, url_prefix="/api/set")
    app.register_blueprint(openapi, url_prefix="/api/openapi")
    app.register_blueprint(openapi_common, url_prefix="/api/openapi")
    app.register_blueprint(
        construct_blueprint_index(), url_prefix="/api/index"
    )  # 首页接口
    app.register_blueprint(authority, url_prefix="/api/authority")
    app.register_blueprint(home, url_prefix="/api/home")
    app.register_blueprint(appuser, url_prefix="/api/appuser")
    app.register_blueprint(wxnotify, url_prefix="/api/wxnotify")
    app.register_blueprint(algorithm, url_prefix="/api/algorithm")
    app.register_blueprint(algorithmModel, url_prefix="/api/algorithm_model")
    app.register_blueprint(algorithmGroup, url_prefix="/api/algorithm_group")
    app.register_blueprint(algorithmConfig, url_prefix="/api/algorithm_config")
    app.register_blueprint(algorithmWarn, url_prefix="/api/algorithm_warn")
    app.register_blueprint(algorithmNotice, url_prefix="/api/algorithm_notice")
    app.register_blueprint(model_group, url_prefix="/api/model_group")
    app.register_blueprint(txl, url_prefix="/api/txl")
    app.register_blueprint(energy, url_prefix="/api/energy")


def before_request(app):
    if os.environ.get("ENVIRONMENT") == "1":
        request.flag = {"dataId": 0}
        # 本地环境
        return utilsapp.utils.ok(msg="本地环境免验证")
    headers = request.headers
    url = request.path
    pass_url = [
        "/",
        "/api/user/login",
        "/api/appuser/login",
        "/api/appuser/login/djc",
        "/api/common/fontBold",
        "/api/common/fontRegular",
        "/api/report/download",
        "/report/download",
        "/api/mqtt/add",
        "/api/report/down/sys",
    ]
    url_in_pass = [
        "openapi",
        "/static/html/",
        "upload",
        "outer",
        "inner",
        "report/viewpdf",
        "domain/fallWave",
        "statistics",
        "health",
    ]
    if "api" not in url or url in pass_url or any(t in url for t in url_in_pass):
        return utilsapp.utils.ok(msg="免验证URL")
    else:
        if "Authorization" not in headers:
            return {"msg": "未登录", "code": 10000}
        else:
            ua = headers["User-Agent"].lower()
            if "android" in ua or "iphone" in ua or "mobile" in ua:
                source = 0
            else:
                source = 1
            token = headers["Authorization"]
            res = verify_token(
                token, app.config["settings"]["SECRET_KEY"], source
            )  # 解析token

            if res["code"] != 0:  # token 验证不成功
                return res

            return res


def create_db_pool(app):
    dbconfig = app.config["settings"]["mysql"]
    # 创建数据库连接池
    app.db_pool = PooledDB(
        creator=pymysql,  # 指定创建连接的库
        host=dbconfig["host"],
        port=dbconfig["port"],
        user=dbconfig["user"],
        password=dbconfig["password"],
        database=dbconfig["dbname"],
        autocommit=True,  # 自动提交事务
        maxconnections=100,  # 连接池中最大连接数
        charset="utf8",
        mincached=5,
        maxcached=10,
        maxshared=20,
    )
    if "mongodb" in app.config["settings"]:
        mgc = app.config["settings"]["mongodb"]
        user = mgc.get("user", "").strip()
        password = mgc.get("password", "").strip()
        if password:
            # 需要认证
            connection_string = (
                f"mongodb://{parse.quote_plus(user)}:"
                f"{parse.quote_plus(password)}@"
                f'{mgc["host"]}:{mgc["port"]}/'
            )
        else:
            # 不需要认证
            connection_string = f'mongodb://{mgc["host"]}:{mgc["port"]}/'

        if 'url' in mgc:
            connection_string = mgc['url']

        app.mgdb = MongoClient(connection_string)

    if "redis" in app.config["settings"]:
        r_config = app.config["settings"]["redis"]
        redis_pool = redis.ConnectionPool(
            host=r_config["host"],
            port=r_config["port"],
            db=r_config["db"],
            password=r_config["password"],
            decode_responses=True,
        )
        app.redis = redis.Redis(connection_pool=redis_pool)


class CustomJSONEncoder(JSONEncoder):
    def default(self, obj):
        if isinstance(obj, datetime):
            return obj.strftime("%Y-%m-%d %H:%M:%S")
        elif isinstance(obj, date):
            return obj.strftime("%Y-%m-%d")
        else:
            return JSONEncoder.default(self, obj)